import com.google.common.collect.LinkedHashMultimap;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.*;
import static org.jsoup.Jsoup.connect;

/**
 * User: Christian Dadswell
 * Date: 13/03/13
 * Time: 20:03
 */

public class parser_BBCRadio {

    public static LinkedHashMap<String, String> stations = new LinkedHashMap();
    public static LinkedHashMap<String, String> allStations = new LinkedHashMap();
    public static LinkedHashMap<String, String> scheduleDatesUrl = new LinkedHashMap();
    public static LinkedHashMap<String, String> broadcastDurations = new LinkedHashMap<String, String>();

    public static String scheduleDateText;
    public static String bDurations = "";
    public static String bEpisodes = "";
    public static String bTitles = "";
    public static String bSubtitles = "";
    public static String bSynopsis = "";

    public static String GetTitle(String url) {
        functions_Strings.print(":: Method :: GetTitle");
        String title = JsoupConnect(url).title();
        return title;
    }

    public static LinkedHashMap GetStations(String url, String locality) throws IOException {
        functions_Strings.print(":: Method :: GetStations");
        LinkedHashMap<String, String> temp_stations = new LinkedHashMap();
        Document stationsDoc = JsoupConnect(url);
        Element nationalRadio = stationsDoc.getElementById(locality);
        Elements stationLinks = nationalRadio.getElementsByTag("a");

        for (Element stationUrls : stationLinks) {
            String linkHref = stationUrls.attr("abs:href");
            String linkText = stationUrls.text();
            temp_stations.put(linkText, linkHref);
            stations.put(linkText, linkHref);
        }
        functions_Json.WriteStationsPerRegionToJson(temp_stations, locality);
        return stations;
    }

    /* Method to get all station names and schedule urls*/
    public static LinkedHashMap GetAllStations() {
        functions_Strings.print(":: Method :: GetAllStations");

        if(functions_fileio.FileOrDirectoryExists(constants.stationsDir + "\\national.json")) {
            // read from json and put in lhm stations
            stations.putAll(functions_Json.ReadStationsFromJson("national"));
        }else{
            try {
                GetStations("http://www.bbc.co.uk/radio/schedules", "national");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if(functions_fileio.FileOrDirectoryExists(constants.stationsDir + "\\regional.json")) {
            // read from json and put in lhm stations
            stations.putAll(functions_Json.ReadStationsFromJson("regional"));
        }else{
            try {
                GetStations("http://www.bbc.co.uk/radio/schedules", "regional");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if(functions_fileio.FileOrDirectoryExists(constants.stationsDir + "\\local.json")){
            // read from json and put in lhm stations
            stations.putAll(functions_Json.ReadStationsFromJson("local"));
        }else{
            try {
                GetStations("http://www.bbc.co.uk/radio/schedules", "local");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        allStations.putAll(stations);
        return allStations;
    }

    /* Method to get schedule dates for a station */
    public static void GetScheduleUrlsForStationByStation(String stationName) {
        functions_Strings.print(":: Method :: GetScheduleUrlsForStationByStation");
        String stationScheduleUrl = allStations.get(stationName);
        Document stationDoc = JsoupConnect(stationScheduleUrl);

        Element radioSchedule = stationDoc.getElementById("daynav");
        Elements stationDates = radioSchedule.getElementsByTag("a");

        for (Element stationUrls : stationDates) {
            String scheduleHref = stationUrls.attr("abs:href");
            // Get right most part of URL, strip the /. This will become the KEY for the gson schedulesDateUrl map
            String dateText = functions_Strings.GetRight(scheduleHref,10).replaceAll("/","");
            scheduleDatesUrl.put(dateText, scheduleHref);
        }
        functions_Json.WriteStationSchedulesPerStationToJson(stationName, stationScheduleUrl, scheduleDatesUrl);
    }

    // Method to retrieve ALL broadcast details for a station
    public static void GetBroadcastsForStationByUrl(String stationName, String stationScheduleUrl, String scheduleDateSearched) {
        functions_Strings.print(":: Method :: GetBroadcastsForStationByUrl");
        Document stationDoc = JsoupConnect(stationScheduleUrl);

        //String[] arrPName = Func_Strings.stringToArray(getPodText(), "#");
/*        //LinkedHashMap<String, String> broadcastDurations = new LinkedHashMap<String, String>();
        List<String> broadcastEpisodes = new ArrayList<String>();
        List<String> broadcastTitles = new ArrayList<String>();
        List<String> broadcastSubTitles = new ArrayList<String>();
        List<String> broadcastSynopsises = new ArrayList<String>();*/

        //ArrayList<String> broadcastDurationsList = new ArrayList<String>();
        //LinkedHashMultimap broadcastDetailsMap = LinkedHashMultimap.create();

        Element schedule = stationDoc.getElementById("introduction");
        Elements date = schedule.getElementsByClass("date");
        scheduleDateText = date.text();
        Element broadcasts = stationDoc.getElementById("broadcasts");
        Elements times = broadcasts.getElementsByClass("broadcast-item--timetitle");
        Elements episode = broadcasts.select("a.broadcast-item--episode");
        Elements titles = broadcasts.getElementsByClass("programme-object--title");
        Elements subtitles = broadcasts.getElementsByClass("programme-object--subtitle");
        Elements synopsis = broadcasts.getElementsByClass("programme-object--synopsis");

        // Get times
        for (Element broadcastTimes : times) {
            //broadcastDurations.add(broadcastTimes.text());
            bDurations = bDurations + broadcastTimes.text() + "#";
        }
        // Get episode
        for (Element broadcastEpisode : episode) {
            //broadcastEpisodes.add(broadcastEpisode.attr("abs:href"));
            bEpisodes = bEpisodes + broadcastEpisode.attr("abs:href") + "#";
        }
        // Get broadcast titles
        for (Element broadcastTitle : titles) {
            //broadcastTitles.add(broadcastTitle.text());
            bTitles = bTitles + broadcastTitle.text() + "#";
        }
        // Get broadcast subtitles
        for (Element broadcastSubTitle : subtitles) {
            //broadcastSubTitles.add(broadcastSubTitle.text());
            bSubtitles = bSubtitles + broadcastSubTitle.text() + "#";
        }
        // Get broadcast synopsis
        for (Element broadcastSynopsis : synopsis) {
            //broadcastSynopsises.add(broadcastSynopsis.text());
            bSynopsis = bSynopsis + broadcastSynopsis.text() + "#";
        }

        // gson here
        functions_Json.WriteStationBroadcastsToJSON(stationName, stationScheduleUrl,
                functions_Strings.ReturnBBCScheduleDate(scheduleDateSearched),
                scheduleDateText, bDurations, bEpisodes, bTitles, bSubtitles, bSynopsis);

        //for(int a=0; a<broadcastDurations.size(); a++)
            //broadcastDurationsList.add(broadcastDurations[a]);
/*
        LinkedHashMultimap lhmmPInfo = LinkedHashMultimap.create();
        ArrayList<String> alPInfo = new ArrayList<String>();

        // CONVERT TEXT STRINGS INTO ARRAYS AND SEPERATE BY "#"
        String[] arrPName = Func_Strings.stringToArray(getPodText(), "#");
        // STARTS AT 0 HERE
        String[] arrPXml = Func_Strings.stringToArray(getPodXML(), "#");
        String[] arrPImage = Func_Strings.stringToArray(getPodImg(), "#");
        String[] arrPDescription = Func_Strings.stringToArray(getPodDescription(), "#");
        String[] arrPFlavour = Func_Strings.stringToArray(getPodFlavour(), "#");
        String[] arrPDuration = Func_Strings.stringToArray(getPodDuration(), "#");
        String[] arrPPage = Func_Strings.stringToArray(getPodPage(), "#");
        String[] arrPGenre = Func_Strings.stringToArray(getPodGenre(), "#");

        // CREATE KEY ARRAYLIST
        for (int i=0; i<arrPName.length; i++)
            alPInfo.add(arrPName[i]);

        // ADD VALUES TO LINKEDHASHMULTIMAP
        for (int j=0; j<arrPXml.length; j++)
            lhmmPInfo.put(alPInfo.get(j), arrPXml[j]);
        for (int k=0; k<arrPImage.length; k++)
            lhmmPInfo.put(alPInfo.get(k), arrPImage[k]);
        for (int l=0; l<arrPDescription.length; l++)
            lhmmPInfo.put(alPInfo.get(l), arrPDescription[l]);
        for (int m=0; m<arrPFlavour.length; m++)
            lhmmPInfo.put(alPbcInfo.get(m), arrPFlavour[m]);
        for (int n=0; n<arrPDuration.length; n++)
            lhmmPInfo.put(alPInfo.get(n), arrPDuration[n]);
        for (int o=0; o<arrPPage.length; o++)
            lhmmPInfo.put(alPInfo.get(o), arrPPage[o]);
        for (int p=0; p<arrPGenre.length; p++)
            lhmmPInfo.put(alPInfo.get(p), arrPGenre[p]);*/

    }

    // Method to retrieve broadcast details for a station by its period of the day
    public static void GetScheduleDetailsForStationByPeriod(String stationsScheduleUrl, String periodName) {
        functions_Strings.print(":: Method :: GetScheduleDetailsForStationByUrl");
        Document stationDoc = JsoupConnect(stationsScheduleUrl);

        List<String> broadcastDurations = new ArrayList<String>();
        List<String> broadcastEpisodes = new ArrayList<String>();
        List<String> broadcastTitles = new ArrayList<String>();
        List<String> broadcastSubTitles = new ArrayList<String>();
        List<String> broadcastSynopsises = new ArrayList<String>();

        Element schedule = stationDoc.getElementById("introduction");
        Elements date = schedule.getElementsByClass("date");

        Element period = stationDoc.select("li:contains(" + periodName + ")").first();
        Elements times = period.getElementsByClass("broadcast-item--timetitle");
        Elements episode = period.select("a.broadcast-item--episode");
        Elements titles = period.getElementsByClass("programme-object--title");
        Elements subtitles = period.getElementsByClass("programme-object--subtitle");
        Elements synopsis = period.getElementsByClass("programme-object--synopsis");

        // Get schedule date
        for (Element scheduleDate : date) {
            String scheduleDateText = scheduleDate.text();
            functions_Strings.print(scheduleDateText);
        }

        // Get times
        for (Element broadcastTimes : times) {
            broadcastDurations.add(broadcastTimes.text());
        }

        // Get episode
        for (Element broadcastEpisode : episode) {
            broadcastEpisodes.add(episode.attr("abs:href"));
        }

        // Get broadcast titles
        for (Element broadcastTitle : titles) {
            broadcastTitles.add(broadcastTitle.text());
        }

        // Get broadcast subtitles
        for (Element broadcastSubTitle : subtitles) {
            broadcastSubTitles.add(broadcastSubTitle.text());
        }

        // Get broadcast synopsis
        for (Element broadcastSynopsis : synopsis) {
            broadcastSynopsises.add(broadcastSynopsis.text());
        }
    }

    /* Method to get schedule times for a specific date
    * Must be passed a station name to get the correct station schedule url
    * Must also be passed a date yyyy/MM/dd
    */
    public static void GetScheduledBroadcastsForStationByDate(String bbcStationName, String scheduleDateToSearch) {
        functions_Strings.print(":: Method :: GetScheduledBroadcastsForStationByDate");
        String stationName = functions_Strings.ReturnShortStationName(bbcStationName);
        //Return given date as BBC date 20130401
        String bbcScheduleDate = functions_Strings.ReturnBBCScheduleDate(scheduleDateToSearch);

        //Check if we have a json file already for that date
        if(functions_fileio.FileOrDirectoryExists(constants.broadcastStationsDir + stationName + "\\" + bbcScheduleDate + ".json")){
            //File already exists, no need to get again
            functions_Strings.print(bbcScheduleDate + ".json already exists");
        }else{
            //Check that date passed is available from current schedule dates
            if(DoesStationScheduleDateExist(stationName, bbcScheduleDate)) {
                // get the scheduledate url
                String stationsScheduleUrl = functions_Json.ReturnScheduleUrlFromJsonByBBCScheduleDate(stationName, bbcScheduleDate);
                GetBroadcastsForStationByUrl(stationName, stationsScheduleUrl, scheduleDateToSearch);
            }else{
                // schedule date not available
                functions_Strings.print("Schedule date: " + scheduleDateToSearch + " does not have a url.");
            }
        }
    }

    // Method to check that a station schedule date exists to be able to retrieve a url
    public static boolean DoesStationScheduleDateExist(String stationName, String bbcScheduleDate) {
        functions_Strings.print(":: Method :: DoesStationScheduleDateExist");
        LinkedHashMap<String, String> listScheduleUrls = null;
        // Read values from station schedule json into list.
        listScheduleUrls = functions_Json.ReadScheduleUrlsFromJson(stationName);

        // Look for scheduleUrl by BBC date
        // Map get by bbcscheduledate
        boolean bbcScheduleDateExists = listScheduleUrls.containsKey(bbcScheduleDate);
        System.out.println("Are schedules available for " + bbcScheduleDate + " ?: " + bbcScheduleDateExists);

        return bbcScheduleDateExists;
    }

    // Method return a schedule url by station name - http://www.bbc.co.uk/asiannetwork/programmes/schedules
    public static String GetMainStationScheduleUrl(String stationName) {
        functions_Strings.print(":: Method :: GetStationScheduleUrl");
        String stationUrl;
        stationUrl = allStations.get(stationName);
        return stationUrl;
    }

    /* Method to show contents of any hashmap */
    public static String ShowHashMap(HashMap hashmapToDisplay) {
        functions_Strings.print(":: Method :: ShowHashMap");
        GetAllStations();
        Iterator iter = hashmapToDisplay.keySet().iterator();

        while (iter.hasNext()) {
            String key = (String) iter.next();
            String val = (String) hashmapToDisplay.get(key);
            functions_Strings.print(key + " " + val);
        }
        return null;
    }

    // Jsoup connection method
    private static Document JsoupConnect(String url) {
        functions_Strings.print(":: Method :: JsoupConnect");
        Document doc = null;
        try {
            doc = connect(url)
                    .data("query", "jsoup")
                    .userAgent("Christian Dadswell")
                    .timeout(3000)
                    .get();
        } catch (IOException e) {
            functions_Strings.print("No internet connection, or BBC website down");
            e.printStackTrace();
        }
        return doc;
    }

}
